
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class ReduceAndCollectTest {
    /**
     * 计算商品平均价格
     */
    @Test
    public void reduceTest() {
        /*
         * 订单对象
         */
        @Data
        @AllArgsConstructor
        class Order {
            // 订单编号
            private Integer id;
            // 商品数量
            private Integer productCount;
            // 消费总金额
            private Double totalAmount;
        }

        ArrayList<Order> list = Lists.newArrayList();
        list.add(new Order(1, 2, 25.12));
        list.add(new Order(2, 5, 257.23));
        list.add(new Order(3, 3, 23332.12));

        Order result = list.stream()
                .parallel()
                .reduce(
                        // 初始值
                        new Order(0, 0, 0.0),

                        // Stream中两个元素的计算逻辑
                        (Order order1, Order order2) -> {
                            System.out.println("执行 计算逻辑 方法！！！");
                            int productCount = order1.getProductCount() + order2.getProductCount();
                            double totalAmount = order1.getTotalAmount() + order2.getTotalAmount();
                            return new Order(0, productCount, totalAmount);
                        },

                        // 并行情况下，多个并行结果如何合并
                        (Order order1, Order order2) -> {
                            System.out.println("执行 合并 方法！！！");
                            int productCount = order1.getProductCount() + order2.getProductCount();
                            double totalAmount = order1.getTotalAmount() + order2.getTotalAmount();
                            return new Order(0, productCount, totalAmount);
                        }
                );
        System.out.println(JSON.toJSONString(result, true));
    }

    @Test
    public void collectTest() {
        /*
         * 订单对象
         */
        @Data
        @AllArgsConstructor
        class Order {
            // 订单编号
            private Integer id;
            // 用户账号
            private String account;
            // 商品数量
            private Integer productCount;
            // 消费总金额
            private Double totalAmount;
        }

        ArrayList<Order> list = Lists.newArrayList();
        list.add(new Order(1, "孙悟空", 2, 25.12));
        list.add(new Order(2, "孙悟空", 5, 257.23));
        list.add(new Order(3, "猪八戒", 3, 23332.12));

        // Map<用户账号，订单（数量和金额）>
        Map<String, Order> result = list.stream()
                .parallel()
                .collect(
                        () -> {
                            System.out.println("执行 初始化容器 操作！！！");
//                            return new HashMap<String, Order>();
                            return new HashMap<>();
                        },
                        (HashMap<String, Order> map, Order newOrder) -> {
                            System.out.println("执行 新元素添加到容器 操作！！！");
                            String account = newOrder.getAccount();
                            // 如果此账号已经存在了，将新的订单数据累加上
                            if (map.containsKey(account)) {
                                Order order = map.get(account);
                                order.setProductCount(order.getProductCount() + newOrder.getProductCount());
                                order.setTotalAmount(order.getTotalAmount() + newOrder.getTotalAmount());
                            }
                            // 如果不存在，直接将新的订单存入map
                            else {
                                map.put(account, newOrder);
                            }
                        },
                        (HashMap<String, Order> map1, HashMap<String, Order> map2) -> {
                            System.out.println("执行 并行结果合并 操作！！！");
                            // TODO: 一定要将数据合并到map1上，因为collect是将map1的结果返回
                            map2.forEach((key, value) -> {
                                // map的merge方法：如果key不存在map中，则将key-value插入到map
                                //                如果key存在map中，则将map中key对应的的value和参数的value使用参数3做一个合并，结果作为map中key的值
                                map1.merge(key, value, (order1, order2) -> {
                                    return new Order(0, key, order1.getProductCount() + order2.getProductCount(),
                                            order1.getTotalAmount() + order2.getTotalAmount());
                                });
                            });
                        }
                );
        System.out.println(JSON.toJSONString(result, true));
    }
}
